/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package supermarket;

import java.io.File;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import model.Checks;
import model.Customer;
import model.ProductPurchase;
import model.Purchase;
import model.Store;
import model.StoreProduct;


/**
 * 
 * 
 * 
 *
 * @author root
 */
public class CustomerThread extends Thread {
    
       
    
    public static EntityManagerFactory emth; 
    public  static int accessMembers=0;
    private final EntityManager emt;
    private final   EntityManager emth2;
    int failedtries = 1;
    Customer customer;
    static Boolean accessXml=false;
    Boolean completed=false;
    ArrayList<Timestamp> timestampList = new ArrayList<>();
    
    
    public  CustomerThread(Customer customer){
         EntityManagerFactory emfth = Persistence.createEntityManagerFactory("SuperMarketPU");
       emt = emfth.createEntityManager(); 
       
       EntityManagerFactory emfth2 = Persistence.createEntityManagerFactory("SuperMarketPU2");
        emth2 = emfth2.createEntityManager(); 
        
        this.customer=customer;
        
    }
    
    
    
    public void run(){
        
        Random rand = new Random();
        
        emt.getTransaction().begin();
        
        int listSize; //αποθηκεύει τον αριθμό καταστημάτων για να γίνει τυχαία επιλογή
        
        int random;
        
            
        
        
        //Τυχαία επιλογή καταστήματος
        TypedQuery<Store> q1 = emt.createNamedQuery("Store.findAll", Store.class);
        List<Store> storeList = q1.getResultList();
        
        listSize = storeList.size();
        
        random = rand.nextInt(listSize); //γίνεται η επολογή καταστήματος
        
        Store store = storeList.get(random);
        
      
        
        
       
       //Τυχαία επιλογή προϊόντων
        
        Query q3 = emt.createQuery(
                "SELECT c FROM StoreProduct c WHERE c.store = :storeId")
                .setParameter("storeId", store);
        List<StoreProduct> storeProductList = q3.getResultList();
        
        Random rand1 = new Random();
        
        Random rand2 = new Random();  
        
        List<ProductPurchase> productPurchaseList = new ArrayList<>();
        
        Purchase purchase = new Purchase();
        
        float totalPrice =0;
        int totalPoints =0;
        
        random = rand.nextInt(20)+1; //20 προϊόντα max
        for(int i=0;i<random;i++){
            
            int randomProduct = rand2.nextInt(storeProductList.size()); //τυχαίο προϊόν
            int randomQuantity = rand1.nextInt(5)+1; //τυχαία ποσότητα
            
            ProductPurchase pp = new ProductPurchase(storeProductList.get(randomProduct).getProduct(), purchase, randomQuantity);
           
            
            //υπολογισμός συνολικής τιμής και πόντων
            totalPrice = totalPrice + randomQuantity*(storeProductList.get(randomProduct).getProduct().getPrice());
            totalPoints = totalPoints + randomQuantity*(storeProductList.get(randomProduct).getProduct().getPoints());
               
            productPurchaseList.add(pp);
            
              }
          
        //υπολογισμός επιταγών
        
        int checks = totalPoints / 200;
        if (checks>0)
        {
            totalPoints = totalPoints-checks*200;
            
            for (int i=0;i<checks;i++){
                       
                       Checks check = new Checks();
                       check.setCode(rand.nextInt(9999 - 1000));
                       Date date = new Date();
                       check.setDatetime(date.toString());
                       check.setValid("ΝΑΙ");
                       check.setOwner(customer);
                       emt.persist(check);
                       
                   }
                    
        }
         
       purchase.setAmount(totalPrice);
       purchase.setCustomer(customer);
       purchase.setStore(store);
       Date date = new Date();
       purchase.setDatetime(date);
       purchase.setPointsEarned(totalPoints);
       purchase.setProductPurchaseList(productPurchaseList);
       purchase.setDelivery(rand.nextBoolean());
       purchase.setAmount(totalPrice);
       purchase.setPointsEarned(totalPoints);
        
       
       emt.persist(purchase);
       
             boolean result=false;
        
             boolean accessResult = false;
             
          Timestamp timestamp;
                 
        while(true){
            
           
             
             timestamp = grandAccess(this); //κάνει αίτηση για πρόσβαση
            
            
        if(timestamp==null){//η αίτηση γίνεται δεκτή
            
            
            
            
          try {
              Authority access = new Authority();
               timestamp = access.accessAuth(customer);
              timestampList.add(timestamp);
             
        } catch (InterruptedException ex) {
            Logger.getLogger(CustomerThread.class.getName()).log(Level.SEVERE, null, ex);
        }  
          if (timestamp!=null)//αποτέλεσμα από τον έλεγχο με την εξωτ. βάση
          {
             
             emt.getTransaction().commit();
             while (true){
             Boolean res = grandaccessXml();
             
             if (res==true){
              
                 completed=true;
              System.out.println("     Completed  " + customer.getFirstName()+" "+customer.getLastName()); 
              createXml(completed);
              dropaccessXml();
              break;
             } 
               
             
             }
           
          dropAccess();
          
           break;
          }
          else 
          {
              
              dropAccess();
              this.stop();
          }
        }
        
        else try {//αποτυχημένες προσπάθειες
            timestampList.add(timestamp);
            
            failedtries = failedtries +1;
            if (failedtries>3)
            {
                
                System.out.println("                                                    Failed "+customer.getFirstName()+" "+customer.getLastName());
                emt.getTransaction().commit();
                
                while (true){
             Boolean res = grandaccessXml();
             
             if (res==true){
              
                 completed=false;
              createXml(completed);
              dropaccessXml();
              break;
             } 
                  }
             
                         break;
                
            }
            
           sleep(rand.nextInt(10000)+10);//τυχαίο sleep για επαναπροσπάθεια
            
        } 
        catch (InterruptedException ex) {
            Logger.getLogger(CustomerThread.class.getName()).log(Level.SEVERE, null, ex);
        }
    
        }
              
    }
    


    
     public static synchronized Timestamp grandAccess(CustomerThread cuThread){
        java.util.Date date= new java.util.Date();
          
       
        
        // System.out.println(new Timestamp(date.getTime()));
         
               
         if(accessMembers<2){
            accessMembers = accessMembers+1;
            
            return null;
         }
         
         else
         {
             
             return  new Timestamp(date.getTime());
         }
        }
        
    public static synchronized void dropAccess(){
            accessMembers= accessMembers-1;
                    }
    
    public  void createXml(Boolean completed){
        
             
         File xmlFile = new File("purchases.xml");
        PurchaseXMLManager purchaseXMLWriter = new PurchaseXMLManager(xmlFile,failedtries,this,completed,timestampList);
         
         TypedQuery<Purchase> allPurchasesQuery = emt.createNamedQuery("Purchase.findAll", Purchase.class);
        List<Purchase> purchaseResults = allPurchasesQuery.getResultList();                    
        purchaseXMLWriter.writeXML(purchaseResults);
        
        System.out.println ( "                Το αρχείο XML δημιουργήθηκε με επιτυχία" );                    
        try {
            emt.getTransaction().begin();
            for (Purchase p:purchaseResults){
                emt.remove(p);
            }
            emt.getTransaction().commit();
            //System.out.println("                Επιτυχής Διαγραφή συναλλαγών!");            
            //System.out.println(" ");
        } catch (Exception e) {
            e.printStackTrace();
            emt.getTransaction().rollback();
        }   
         
        
    } 
    
    
    public synchronized static boolean grandaccessXml(){
        if (accessXml==false)
        {
        accessXml=true;
        return true;
                }
        else return false;
    }
    
     public synchronized static void dropaccessXml(){
        accessXml=false;
           
    }
    
}
    
    
    
         
    
    
    

